#include <string.h>
#include "main.h"
#include "app_lora.h"
#include "app_debug.h"
#include "radio.h"
#include "sx1276Regs-Lora.h"

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "timers.h"
#include "semphr.h"

#define LORA_FREQUENCY  434000000    
#define TX_OUTPUT_POWER 20      // dBm
#define LORA_BANDWIDTH 0        // [0: 125 kHz,  1: 250 kHz,  2: 500 kHz,  3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7..SF12]
#define LORA_CODINGRATE 1       // [1: 4/5,  2: 4/6,  3: 4/7,  4: 4/8]
#define LORA_PREAMBLE_LENGTH 8  // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT 5   // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false

#define MAX_SEND_BUF_LEN    128

static QueueHandle_t que_send=NULL;
static QueueHandle_t que_recv=NULL;
static TaskHandle_t task_lora=NULL;

static bool is_inited=false;



typedef enum
{
    LSEND_STATE_CHECK_RSSI,
    LSEND_STATE_SEND,
    LSEND_STATE_WAIT_SEND,
    LSEND_STATE_WAIT_ACK,
}lora_send_state_t;

typedef enum
{
    LORA_RESULT_OK,
    LORA_RESULT_TIMEOUT,
    LORA_RESULT_ERROR,
}lora_result_e;

static struct
{
    uint8_t send_buf[MAX_SEND_BUF_LEN];
    uint8_t send_len;
    uint8_t*  precv;
    uint8_t*  precv_len;
}loractl;


static void lora_task(void *param);

static void tx_done_handler()
{
    uint8_t result=LORA_RESULT_OK;
    Radio.Sleep();
    xQueueSend(que_send,&result,100);
    //HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);

}
static void tx_timeout_handler()
{
    uint8_t result=LORA_RESULT_TIMEOUT;
    Radio.Sleep();
    xQueueSend(que_send,&result,100);
}

static void rx_done_handler( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
    uint8_t result=LORA_RESULT_OK;
    if(size<(*loractl.precv_len))*loractl.precv_len=size;
    memcpy(loractl.precv,payload,*loractl.precv_len);
    Radio.Sleep();
    xQueueSend(que_recv,&result,100);
}
static void rx_timeout_handler()
{
    uint8_t result=LORA_RESULT_TIMEOUT;
    Radio.Sleep();
    xQueueSend(que_recv,&result,100);
}
static void rx_error_handler()
{
    uint8_t result=LORA_RESULT_ERROR;
    Radio.Sleep();
    xQueueSend(que_recv,&result,100);
}



static void lora_params_config()
{
    static RadioEvents_t RadioEvents = {0};
    RadioEvents.TxDone = tx_done_handler;
    RadioEvents.RxDone = rx_done_handler;
    RadioEvents.TxTimeout = tx_timeout_handler;
    RadioEvents.RxTimeout = rx_timeout_handler;
    RadioEvents.RxError = rx_error_handler;

    Radio.Init(&RadioEvents);

    Radio.SetChannel(LORA_FREQUENCY);
    Radio.SetTxConfig(MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
                      LORA_SPREADING_FACTOR, LORA_CODINGRATE,
                      LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
                      true, 0, 0, LORA_IQ_INVERSION_ON, 1000);
    Radio.SetRxConfig(MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
                      LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
                      LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
                      0, true, 0, 0, LORA_IQ_INVERSION_ON, true);
    
    Radio.Sleep();
    Radio.Write(REG_LR_SYNCWORD,0x23);
}


void lora_init()
{
    lora_params_config();

    que_send=xQueueCreate(1,sizeof(uint8_t));
    que_recv=xQueueCreate(1,sizeof(uint8_t));
    xTaskCreate(lora_task, "loraTask", 128, NULL, 2, &task_lora);
    
    is_inited =true;
}

static uint8_t lora_data_pack(lora_send_pack_t pack,uint8_t *buffer,uint8_t max_buffer_len)
{
    uint8_t counter;
    if((pack.len+4)>max_buffer_len)return 0;

    counter=0;
    buffer[counter++]=0x68;
    buffer[counter++]=pack.add;
    buffer[counter++]=pack.cmd;
    buffer[counter++]=pack.len;
    memcpy(buffer,pack.data,pack.len);
    counter+=pack.len;
    return counter;
}

void lora_task(void *param)
{  
    lora_send_pack_t pack;
    while(1)
    {
        //lora_send("12345",5);
        vTaskDelay(5000);
        
    }
}

bool lora_send_data(uint8_t add,uint8_t cmd,uint8_t len,uint8_t *data,bool need_ack)
{
    lora_send_pack_t pack;
    if(que_send==NULL)return false;
    if(len>2)return false;
    pack.add=add;
    pack.cmd=cmd;
    pack.len=len;
    memcpy(pack.data,data,len);
    pack.need_ack=need_ack;

    return xQueueSend(que_send,&pack,1000);
}



bool lora_send(uint8_t *data,uint8_t datalen)
{
    uint8_t err=0;
    uint8_t result;
    if(is_inited==false)return false;
    
    while(err<3)
    {
        if(Radio.IsChannelFree(MODEM_LORA,434000000,-80)==false)
        {
            vTaskDelay((uint32_t)Radio.Random()%50);
            err++;
            continue;
        }
        xQueueReset(que_send);
        Radio.Send(data,datalen);
        if(xQueueReceive(que_send,&result,LORA_SEND_WAIT_TIME)==pdFALSE)return false;
        if(result==LORA_RESULT_OK)return true;
        else if(result==LORA_RESULT_TIMEOUT)return false;
    }

    return false;
    
}
uint8_t lora_send_wait_replay(uint8_t* data,uint8_t datalen,uint8_t *recbuf,uint8_t buflen)
{
    uint8_t result;
    if(is_inited==false)return false;
    xQueueReset(que_recv);
    if(lora_send(data,datalen)==false)return 0;

    loractl.precv=recbuf;
    *loractl.precv_len=buflen;

    Radio.Rx(LORA_RECV_WAIT_TIME);
    if(xQueueReceive(que_recv,&result,LORA_SEND_WAIT_TIME)==pdFALSE)return false;
    if((result==LORA_RESULT_TIMEOUT)||(result==LORA_RESULT_ERROR))
    {
        return false;
    }
    else if(result==LORA_RESULT_OK)
    {
        return true;
    }
    return false;       
}

